package com.yuandian.utils.poi;

import cn.hutool.core.util.ObjectUtil;
import com.yuandian.po.BaseSearch;
import com.yuandian.utils.BeanUtils;
import com.yuandian.utils.YDateUtil;
import com.yuandian.utils.PageDataInfo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author liXin
 * @description Excel表信息
 * @date 2022/4/26
 */
@Data
@Slf4j
public class ExcelTableInfo {

    //私有构造方法
    private ExcelTableInfo(){}

    /**
     * 表头
     */
    private List<List<String>> header;

    /**
     * 工作表名称
     */
    private String sheetName;

    /**
     * excel表名
     */
    private String excelName;

    /**
     * 数据集
     */
    private List<?> dataList;

    /**
     * 导出数据对应的实体
     */
    private Class<?> clazz;

    private ExcelTableInfo(Builder builder){
         this.header = builder.headList;
         this.sheetName = builder.sheetName;
         this.excelName = builder.excelName;
         this.dataList = builder.dataList;
         this.clazz = builder.clazz;
    }

    public static class Builder{

        /**
         * 标题
         */
        private List<String> titleParams;

        /**
         * 表头
         */
        private List<String> headerList;

        /**
         * 工作表名称
         */
        private String sheetName;

        /**
         * excel表名
         */
        private String excelName;

        /**
         * 基础查询条件
         */
        private BaseSearch baseSearch;

        /**
         * 表头和标题的集合
         */
        private List<List<String>> headList;

        /**
         * 导出数据对应的实体
         */
        private Class<?> clazz;

        /**
         * 添加 %后缀字段
         */
        private String[] addSuffixfields;

        /**
         * 转换时间格式
         */
        private String[] transferTimeFormatFields;

        /**
         * 序号字段名称
         */
        private String numberName;

        /**
         * 数据集
         */
        private List<?> dataList = new ArrayList<>();

        public Builder(BaseSearch baseSearch, Class<?> clazz){
            this.baseSearch = baseSearch;
            this.clazz = clazz;
            this.titleParams = new ArrayList<>();
            this.headerList = new ArrayList<>();
            this.excelName = "";
            this.sheetName = "";
            this.headList = new ArrayList<>();
        }

        public Builder setDataList(List<?> dataList){
            this.dataList = dataList;
            return this;
        }

        public Builder setDataListByResult(Object result){
            PageDataInfo pageDataInfo = BeanUtils.cast(result);
            List<?> dataList = null;
            try {
                dataList = BeanUtils.cast(pageDataInfo.getData());
            } catch (Exception e) {
                log.error("所选时间表不存在!但表格需要正常导出.");
            }
            this.dataList = dataList;
            return this;
        }

        public Builder setTitle(List<String> titleParams){
            this.titleParams = titleParams;
            return this;
        }

        public Builder setNumberName(String numberName){
            this.numberName = numberName;
            return this;
        }

        public Builder setHeader(List<String> headerList){
            this.headerList = headerList;
            return this;
        }

        public Builder setSheetName(String sheetName){
            this.sheetName = sheetName;
            return this;
        }

        public Builder setExcelName(String excelName){
            this.excelName = excelName;
            return this;
        }

        public Builder setTimeFormatFields(String  ...field){
            this.transferTimeFormatFields = field;
            return this;
        }

        public Builder setSuffixPercentageFields(String  ...field){
            this.addSuffixfields = field;
            return this;
        }

        public ExcelTableInfo build(){
            //构建大表头
            generateHeadList();
            //格式化字段
            formatterField();
            return new ExcelTableInfo(this);
        }

        //构建大表头
        private void generateHeadList(){
            String formTitleName = ExcelTitleUtils.formTitleName(titleParams, baseSearch.getStartTime(), baseSearch.getEndTime());
            // 表单大标题this
            headerList.forEach(s -> {
                List<String> childHeadList = new ArrayList<>();
                childHeadList.add(formTitleName);
                childHeadList.add(s);
                headList.add(childHeadList);
            });
        }

        //格式化字段
        private void formatterField(){
            if (ObjectUtil.isNotEmpty(this.dataList)){
                //序号
                Integer numberInt = 1;
                Long numberLong = 1L;
                for (Object object : this.dataList) {
                    //填充序号
            if (numberName != null){
                try {
                    Field field = object.getClass().getDeclaredField(numberName);
                    field.setAccessible(true);
                    String typeName = field.getType().getTypeName();
                    if ("java.lang.Integer".equals(typeName)){
                        Method setMethod = object.getClass().getMethod(setMethodName(numberName), Integer.class);
                                setMethod.invoke(object, numberInt++);
                    }
                    if (("java.lang.Long").equals(typeName)){
                        Method setMethod = object.getClass().getMethod(setMethodName(numberName), Long.class);
                                setMethod.invoke(object, numberLong++);
                    }
                } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                    e.printStackTrace();
                    log.info("{}字段不存在或者该字段的get或者set方法不存在", numberName);
                }
            }
                    //填充 % 号
                    setSuffixPercentage(object);
//                   转换时间格式
                    transferTimeFormat(object);
                }
        }
        }

        //添加序号
//        private Integer fill(Object object, Integer number) {
//            if (numberName != null){
//                try {
//                    Field field = object.getClass().getDeclaredField(numberName);
//                    field.setAccessible(true);
//                    String typeName = field.getType().getTypeName();
//                    if ("java.lang.Integer".equals(typeName)){
//                        Method setMethod = object.getClass().getMethod(setMethodName(numberName), Integer.class);
//                        setMethod.invoke(object, number++);
//                    }
//                    if (("java.lang.Long").equals(typeName)){
//                        Method setMethod = object.getClass().getMethod(setMethodName(numberName), Long.class);
//                        setMethod.invoke(object, number++);
//                    }
//                } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
//                    e.printStackTrace();
//                    log.info("{}字段不存在或者该字段的get或者set方法不存在", numberName);
//                }
//            }
//            return number;
//        }

        private void setSuffixPercentage(Object object) {
            if (addSuffixfields != null) {
                for (String fieldName : addSuffixfields) {
                    Method method = null;
                    try {
                        method = object.getClass().getMethod(getMethodName(fieldName));
                        Object value = method.invoke(object);
                        value = Optional.ofNullable(value).orElse("0");
                        if (value instanceof String) {
                            value = (String) value + "%";
                            Method setMethod = object.getClass().getMethod(setMethodName(fieldName), String.class);
                            setMethod.invoke(object, value);
                        }
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                        log.info("{}字段不存在或者该字段的get或者set方法不存在", fieldName);
                    }

                }
            }
        }

        private void transferTimeFormat(Object object) {
            if (transferTimeFormatFields != null){
                for (String fieldName : transferTimeFormatFields) {
                    Method method = null;
                    try {
                        method = object.getClass().getMethod(getMethodName(fieldName));
                        Object value = method.invoke(object);
                        value = Optional.ofNullable(value).orElse("0");
                        if (value instanceof String) {
                            value = YDateUtil.getMinSecond(Double.parseDouble((String) value) / 1000);
                            Method setMethod = object.getClass().getMethod(setMethodName(fieldName), String.class);
                            setMethod.invoke(object, value);
                        }
                    } catch (NoSuchMethodException | IllegalAccessException  | InvocationTargetException e) {
                        e.printStackTrace();
                        log.info("{}字段不存在或者该字段的get或者set方法不存在", fieldName);
                    }
                }
            }
        }
        //首字母大写
        private String upperInitials(String fieldName){
            char[] chars = fieldName.toCharArray();
            if (chars[0] >= 97 && chars[0] <= 122){
                chars[0] -= 32;
            }
            return String.valueOf(chars);
        }

        private String getMethodName(String fieldName){
            return "get" + upperInitials(fieldName);
        }

        private String setMethodName(String fieldName){
            return "set" + upperInitials(fieldName);
        }


    }

    public void exportExcel(HttpServletResponse response) throws IOException {
        ExcelUtil.writeExcel((Class <T>) clazz, excelName, sheetName ,  (List<T>)dataList, header, response);
    }
}
